package com.infra.common.util;

import com.alibaba.fastjson2.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.infra.common.resp.KeyValue;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * 认证工具类
 * 覆盖了对JWT的Token生成，从token中获取用户信息，以及从网关鉴权后的请求头中获取用户信息
 *
 * @author PD
 */
public class AuthUtils {
    private static final String SECRET_KEY = "jwt-a891a8f-5ce5-11ec-bab0-c81f66de7650"; //秘钥
    private static final String ISSUER = "hn-man@live.cn"; //签发人
    /**
     * 令牌KEY
     */
    public static final String AUTHORIZATION = "Authorization";
    /**
     * 用户IDKEY
     */
    public static final String USER_ID = "UserId";

    /**
     * 用户名KEY
     */
    public static final String USER_NAME = "UserName";

    /**
     * 用户昵称KEY
     */
    public static final String NICK_NAME = "NickName";

    /**
     * 组织机构KEY
     */
    public static final String ORGANIZATIONS = "Organizations";

    /**
     * 角色权限KEY
     */
    public static final String ROLES = "Roles";

    /**
     * 鉴权身份KEY
     */
    public static final String AUTHS = "Auths";

    /**
     * 激活标识KEY
     */
    public static final String ACTIVE = "Active";

    /**
     * 生成签名
     *
     * @param userId   用户ID
     * @param userName 用户命名
     * @param nickName 用户昵称
     * @param orgList  组织机构列表
     * @param roleList 角色列表
     * @param authList 身份列表
     * @param active   激活状态
     * @return
     */
    public static String generateToken(Long userId, String userName, String nickName, List<KeyValue> orgList, List<KeyValue> roleList, List<String> authList, boolean active) {
        return generateToken(userId, userName, nickName, orgList, roleList, authList, active, SECRET_KEY);
    }

    public static String generateToken(Long userId, String userName, String nickName, List<KeyValue> orgList, List<KeyValue> roleList, List<String> authList, boolean active, String secretKey) {
        Date now = new Date();
        Algorithm algorithm = Algorithm.HMAC256(secretKey); //算法

        String token = JWT.create()
                .withIssuer(ISSUER) //签发人
                .withIssuedAt(now) //签发时间
                .withSubject(userName) //登陆账号
                .withClaim(AuthUtils.USER_ID, userId) //保存身份标识
                .withClaim(AuthUtils.NICK_NAME, nickName) //保存身份标识
                .withClaim(AuthUtils.ORGANIZATIONS, JSON.toJSONString(orgList)) //保存身份标识
                .withClaim(AuthUtils.ROLES, JSON.toJSONString(roleList)) //保存权限标识
                .withClaim(AuthUtils.AUTHS, StringUtils.join(authList, ",")) //保存权限标识
                .withClaim(AuthUtils.ACTIVE, active)
                .sign(algorithm);
        return token;
    }

    /**
     * 验证token是否有效
     *
     * @param token token令牌
     * @return
     */
    public static boolean verify(String token) {
        return verify(token, SECRET_KEY);
    }

    public static boolean verify(String token, String secretKey) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secretKey); //算法
            JWTVerifier verifier = JWT.require(algorithm)
                    .withIssuer(ISSUER)
                    .build();
            verifier.verify(token);//如果校验有问题会抛出异常。
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }

    /**
     * 获取用户ID
     *
     * @param token token令牌
     * @return
     */
    public static Long getUserId(String token) {
        try {
            return JWT.decode(token).getClaim(AuthUtils.USER_ID).asLong();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 获取用户登陆账号
     *
     * @param token token令牌
     * @return
     */
    public static String getUserName(String token) {
        try {
            return JWT.decode(token).getSubject();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    /**
     * 获取激活状态
     *
     * @param token token令牌
     * @return
     */
    public static boolean isActive(String token) {
        try {
            Boolean isActive = JWT.decode(token).getClaim(AuthUtils.ACTIVE).asBoolean();
            return isActive != null && isActive.booleanValue();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }

    /**
     * 获取用户昵称
     *
     * @param token token令牌
     * @return
     */
    public static String getNickName(String token) {
        try {
            return JWT.decode(token).getClaim(AuthUtils.NICK_NAME).asString();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    /**
     * 获取组织机构
     *
     * @param token token令牌
     * @return
     */
    public static List<KeyValue> getOrgList(String token) {
        try {
            String organization = JWT.decode(token).getClaim(AuthUtils.ORGANIZATIONS).asString();
            return JSON.parseArray(organization, KeyValue.class);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return new ArrayList<>();
    }

    /**
     * 获取角色列表
     *
     * @param token token令牌
     * @return
     */
    public static List<KeyValue> getRoleList(String token) {
        try {
            String roles = JWT.decode(token).getClaim(AuthUtils.ROLES).asString();
            return JSON.parseArray(roles, KeyValue.class);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return new ArrayList<>();
    }

    /**
     * 获取鉴权身份列表
     *
     * @param token token令牌
     * @return
     */
    public static List<String> getAuthList(String token) {
        try {
            String auths = JWT.decode(token).getClaim(AuthUtils.ROLES).asString();
            return Arrays.asList(StringUtils.split(auths, ","));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return new ArrayList<>();
    }

    /**
     * 从token中获取Claims
     *
     * @param token token令牌
     * @return
     */
    public static Map<String, Claim> getClaims(String token) {
        try {
            return JWT.decode(token).getClaims();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return new HashMap<>();
    }
}
